package com.wimcorp.magic.dataloader.test;

import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;

import org.json.simple.JSONArray;
import org.json.simple.JSONObject;
import org.json.simple.parser.JSONParser;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.test.annotation.Rollback;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.testng.AbstractTransactionalTestNGSpringContextTests;
import org.testng.annotations.Test;

import com.wimcorp.magic.data.AbilityData;
import com.wimcorp.magic.data.BehaviourData;
import com.wimcorp.magic.data.CardData;
import com.wimcorp.magic.data.ColorData;
import com.wimcorp.magic.data.CostData;
import com.wimcorp.magic.data.DeckData;
import com.wimcorp.magic.data.SubTypeData;
import com.wimcorp.magic.data.TypeData;
import com.wimcorp.magic.data.dao.AbilityDataDao;
import com.wimcorp.magic.data.dao.BehaviourDataDao;
import com.wimcorp.magic.data.dao.CardDataDao;
import com.wimcorp.magic.data.dao.ColorDataDao;
import com.wimcorp.magic.data.dao.DeckDataDao;
import com.wimcorp.magic.data.dao.SubTypeDataDao;
import com.wimcorp.magic.data.dao.TypeDataDao;

@Test
@ContextConfiguration(locations = { "/applicationContext-magic-the-androiding-data-loader.xml" })
public class LoadCardData extends AbstractTransactionalTestNGSpringContextTests {

	@Autowired
	DeckDataDao deckDataDao;
	@Autowired
	AbilityDataDao abilityDataDao;
	@Autowired
	BehaviourDataDao behaviourDataDao;
	@Autowired
	ColorDataDao colorDataDao;
	@Autowired
	SubTypeDataDao subTypeDataDao;
	@Autowired
	TypeDataDao typeDataDao;

	@Autowired
	CardDataDao cardDataDao;

	HashMap<String, TypeData> typeMap = new HashMap<String, TypeData>();
	Map<String, ColorData> colorMap = new HashMap<String, ColorData>();
	Map<String, SubTypeData> subtypeMap = new HashMap<String, SubTypeData>();
	Map<String, AbilityData> abilityMap = new HashMap<String, AbilityData>();
	Map<String, BehaviourData> behaviourMap = new HashMap<String, BehaviourData>();

	@Rollback(false)
	public void loadCardData() throws IOException {

		try {

			JSONParser parser = new JSONParser();
			String cardSetsFile = "src\\main\\resources\\card-data\\AllSets.json";

			Object cardSets = parser.parse(new InputStreamReader(new FileInputStream(cardSetsFile), "UTF-8"));

			createCardBaseData((JSONObject) cardSets);

			JSONObject jsonObject = (JSONObject) cardSets;

			Set<String> setNames = jsonObject.keySet();
			// String setName = "DDM";
			for (String setName : setNames) {
				JSONObject cardSet = (JSONObject) jsonObject.get(setName);
				Set<CardData> cardData = createCardData(cardSet);
				DeckData deck = new DeckData(setName, cardSet.get("name").toString(), cardData);

				deckDataDao.saveOrUpdate(deck);
			}

		} catch (Exception e) {

			e.printStackTrace();
		}

	}

	private Set<CardData> createCardData(JSONObject cardSet) {
		Set<CardData> cardz = new HashSet<CardData>();
		try {
			JSONArray cards = (JSONArray) cardSet.get("cards");
			for (int i = 0; i < cards.size(); i++) {
				JSONObject card = (JSONObject) cards.get(i);

				long multiverseid = new Long(card.get("multiverseid").toString());

				Object[] types = ((JSONArray) card.get("types")).toArray(new String[((JSONArray) card.get("types"))
						.size()]);
				Object[] colors = card.get("colors") != null ? ((JSONArray) card.get("colors"))
						.toArray(new String[((JSONArray) card.get("colors")).size()]) : new Object[0];

				String name = card.get("name").toString();
				Object[] subtypes = card.get("subtypes") != null ? ((JSONArray) card.get("subtypes"))
						.toArray(new String[((JSONArray) card.get("subtypes")).size()]) : new Object[0];
				String power = card.get("power") != null ? card.get("power").toString() : null;
				String toughness = card.get("toughness") != null ? card.get("toughness").toString() : null;
				String manaCost = card.get("manaCost") != null ? card.get("manaCost").toString() : null;
				String text = card.get("text") != null ? card.get("text").toString() : null;

				String loyalty = card.get("loyalty") != null ? card.get("loyalty").toString() : null;
				int number = -1;
				try {
					number = card.get("number") != null ? new Integer(card.get("number").toString()) : -1;
				} catch (Exception e) {
					System.out.println("not a number... " + e.getMessage());
				}
				int count = new Integer(card.get("count").toString());

				Object[] abilities = card.get("abilities") != null ? ((JSONArray) card.get("abilities"))
						.toArray(new String[((JSONArray) card.get("abilities")).size()]) : new Object[0];
				Object[] behaviours = card.get("behaviour") != null ? ((JSONArray) card.get("behaviour"))
						.toArray(new String[((JSONArray) card.get("behaviour")).size()]) : new Object[0];

				Set<TypeData> typesList = new HashSet<TypeData>();
				if (types != null) {
					for (Object o : types) {
						if (o != null) {
							String type = o.toString();
							try {
								TypeData t = this.typeMap.get(type);
								if (t != null) {
									typesList.add(t);
								}
							} catch (Exception e) {
								e.printStackTrace();
							}

						}
					}
				}

				Set<ColorData> colorsList = new HashSet<ColorData>();
				if (colors != null) {
					for (Object o : colors) {
						if (o != null) {
							try {
								String color = o.toString();
								ColorData c = this.colorMap.get(color);
								if (c != null) {
									colorsList.add(c);
								}
							} catch (Exception e) {
								e.printStackTrace();
							}
						}
					}
				}

				Set<SubTypeData> subtypesList = new HashSet<SubTypeData>();
				if (subtypes != null) {
					for (Object o : subtypes) {
						if (o != null) {
							try {
								String subtype = o.toString();
								SubTypeData s = this.subtypeMap.get(subtype);
								if (s != null) {
									subtypesList.add(s);
								}
							} catch (Exception e) {
								e.printStackTrace();
							}
						}
					}
				}

				Set<AbilityData> abilitiesList = new HashSet<AbilityData>();
				if (subtypes != null) {
					for (Object o : abilities) {
						if (o != null) {
							try {
								String ability = o.toString();
								AbilityData a = this.abilityMap.get(ability);
								if (a != null) {
									abilitiesList.add(a);
								}
							} catch (Exception e) {
								e.printStackTrace();
							}

						}
					}
				}

				Set<BehaviourData> behavioursList = new HashSet<BehaviourData>();
				if (behaviours != null) {
					for (Object o : behaviours) {
						if (o != null) {
							try {
								String behaviour = o.toString();
								BehaviourData b = this.behaviourMap.get(behaviour);
								if (b != null) {
									behavioursList.add(b);
								}
							} catch (Exception e) {
								e.printStackTrace();
							}
						}
					}
				}

				CardData playCard = new CardData(abilitiesList, behavioursList, typesList, colorsList, multiverseid,
						name, subtypesList, power, toughness, manaCost, text, count, number);
				if (loyalty != null) {
					playCard.setLoyalty(new Integer(loyalty));
				}
				cardz.add(playCard);

				// deckCardAssociationDao.saveOrUpdate(deckCardAssociation);
				System.out.println("done " + multiverseid);

			}

		} catch (Exception e) {
			e.printStackTrace();
		}
		return cardz;
	}

	private void createCardBaseData(JSONObject cardSets) {

		JSONObject jsonObject = cardSets;

		Set<String> setNames = jsonObject.keySet();
		for (String setName : setNames) {
			JSONObject cardSet = (JSONObject) jsonObject.get(setName);

			try {
				JSONArray cards = (JSONArray) cardSet.get("cards");
				for (int i = 0; i < cards.size(); i++) {
					JSONObject card = (JSONObject) cards.get(i);

					Object[] types = ((JSONArray) card.get("types")) != null ? ((JSONArray) card.get("types"))
							.toArray(new String[((JSONArray) card.get("types")).size()]) : new Object[0];
					Object[] colors = card.get("colors") != null ? ((JSONArray) card.get("colors"))
							.toArray(new String[((JSONArray) card.get("colors")).size()]) : new Object[0];

					Object[] subtypes = card.get("subtypes") != null ? ((JSONArray) card.get("subtypes"))
							.toArray(new String[((JSONArray) card.get("subtypes")).size()]) : new Object[0];

					Object[] abilities = card.get("abilities") != null ? ((JSONArray) card.get("abilities"))
							.toArray(new String[((JSONArray) card.get("abilities")).size()]) : new Object[0];
					Object[] behaviours = card.get("behaviour") != null ? ((JSONArray) card.get("behaviour"))
							.toArray(new String[((JSONArray) card.get("behaviour")).size()]) : new Object[0];

					if (types != null) {
						for (Object o : types) {
							if (o != null) {
								String type = o.toString();
								try {
									TypeData t = new TypeData(type);

									if (!typeMap.containsKey(type)) {
										typeMap.put(type, t);
									}
								} catch (Exception e) {
									e.printStackTrace();
								}

							}
						}
					}

					if (colors != null) {
						for (Object o : colors) {
							if (o != null) {
								try {
									String color = o.toString();
									ColorData c = new ColorData(color);

									if (!colorMap.containsKey(c)) {
										colorMap.put(color, c);
									}

								} catch (Exception e) {
									e.printStackTrace();
								}
							}
						}
					}

					if (subtypes != null) {
						for (Object o : subtypes) {
							if (o != null) {
								try {
									String subtype = o.toString();
									SubTypeData s = new SubTypeData(subtype);

									if (!subtypeMap.containsKey(s)) {
										subtypeMap.put(subtype, s);
									}

								} catch (Exception e) {
									e.printStackTrace();
								}
							}
						}
					}

					if (abilities != null) {
						for (Object o : abilities) {
							if (o != null) {
								try {
									String ability = o.toString();
									AbilityData a = new AbilityData("", "", new HashSet<CostData>());

									if (!abilityMap.containsKey(a)) {
										abilityMap.put(ability, a);
									}

								} catch (Exception e) {
									e.printStackTrace();
								}

							}
						}
					}

					if (behaviours != null) {
						for (Object o : behaviours) {
							if (o != null) {
								try {
									String behaviour = o.toString();
									BehaviourData b = new BehaviourData(behaviour,"");

									if (!behaviourMap.containsKey(b)) {
										behaviourMap.put(behaviour, b);
									}
								} catch (Exception e) {
									e.printStackTrace();
								}
							}
						}
					}
				}

			} catch (Exception e) {
				e.printStackTrace();
			}
		}

		try {

			for (AbilityData a : abilityMap.values()) {
				abilityDataDao.saveOrUpdate(a);
			}
		} catch (Exception e) {
			e.printStackTrace();
		}
		try {

			for (BehaviourData b : behaviourMap.values()) {
				behaviourDataDao.saveOrUpdate(b);
			}
		} catch (Exception e) {
			e.printStackTrace();
		}
		try {

			for (ColorData c : colorMap.values()) {
				colorDataDao.saveOrUpdate(c);
			}
		} catch (Exception e) {
			e.printStackTrace();
		}
		try {

			for (SubTypeData s : subtypeMap.values()) {
				subTypeDataDao.saveOrUpdate(s);
			}
		} catch (Exception e) {
			e.printStackTrace();
		}
		try {

			for (TypeData t : typeMap.values()) {
				typeDataDao.saveOrUpdate(t);
			}
		} catch (Exception e) {
			e.printStackTrace();
		}

	}

}
